package com.example.demo.service.aiService;

import com.example.demo.enums.EmotionScene;
import com.example.demo.enums.NluResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.chat.prompt.SystemPromptTemplate;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Map;

@Service
public class NluService {

    private final ChatClient chatClient;
    private static final Logger logger = LoggerFactory.getLogger(NluService.class);

    public NluService(ChatClient.Builder chatClientBuilder) {
        this.chatClient = chatClientBuilder.build();
    }

    /**
     * 接收用户文本，调用AI进行NLU分析，并返回经过健壮性处理的结构化结果。
     *
     * @param userText 用户的原始提问
     * @return 经过处理和过滤的 NluResult 对象
     */
    public NluResult performNlu(String userText) {

        // --- 步骤 1: 使用最终优化版的提示词模板 ---
        // 这里的文本完整复制了我们最终确定的“优化版NLU提示词模板”中的指令部分。
        String systemMessage = """
                    ### 1. 角色与任务定义 (Role & Task Definition)
                    你是一个高度专业化的自然语言理解（NLU）引擎。你的任务是接收一段关于情感问题的中文文本，并将其转换为一个结构化的 JSON 对象。
                    你的处理流程分为两步：
                    1.  场景识别 (Scene Recognition): 从下方“场景定义列表”中，为用户输入匹配唯一一个最相关的场景标签。
                    2.  实体提取 (Entity Extraction): 从用户输入中，根据下方“实体类型定义”，提取所有相关的关键信息片段。
                    你的最终输出 **必须** 是一个格式完全正确的、不包含任何额外解释或文本的 JSON 对象。

                    ### 2. 场景定义列表 (Scene Definitions)
                    你必须从以下列表中选择一个 `scene` 标签：
                    {scenes}

                    ### 3. 实体类型定义 (Entity Type Definitions)
                    你必须从文本中提取以下类型的 `entities`：
                    - `PERSON_CORE`: 核心人物 (指代关系中的直接双方)。例如: "我", "我女朋友", "我老婆", "我男朋友", "我老公"
                    - `PERSON_RELATED`: 关系人物 (指代核心关系之外的、但与事件相关的第三方)。例如: "她妈妈", "我闺蜜", "他兄弟", "前女友", "男闺蜜"
                    - `TIME`: 时间信息 (e.g., "昨天晚上", "三个月了", "下周末")
                    - `LOCATION`: 地点或平台 (e.g., "在微信上", "公司楼下", "电话里")
                    - `EVENT`: 发生的具体事件 (e.g., "吵架", "冷战", "约会", "送礼物", "不回消息")
                    - `REASON`: 导致事件的直接原因 (仅在无法从其他实体推断时提取)。例如: "因为他忘了纪念日", "由于工作很忙"
                    - `EMOTION`: 用户直接或间接表达的情绪 (e.g., "好烦", "很开心", "难过", "有点失望")
                    - `STATUS`: 当前的关系状态 (e.g., "异地恋", "已分手", "暧昧期")

                    ### 4. 格式与规则 (Formatting & Rules)
                        - **规则1：** 最终输出必须是一个单独的、格式严格正确的 JSON 对象，不能有任何前缀、后缀或解释性文字。
                - **规则2：** JSON 根对象必须包含 `scene` (字符串) 和 `entities` (对象数组) 两个键。实体对象的键名必须是 `type` 和 `value`。
                - **规则3：** 避免信息冗余。如果一个原因可以从其他实体（如人物和事件）中清晰推断出来，就**不要**单独提取 `REASON` 实体。
                - **规则4：** 如果找不到任何实体，`entities` 字段的值必须是一个空数组 `[]`。
                - **规则5：** 如果场景无法识别，`scene` 字段的值必须是 `UNKNOWN`。
                """;

        var scenes = List.of(EmotionScene.values());
        SystemPromptTemplate systemPromptTemplate = new SystemPromptTemplate(systemMessage);
        Prompt prompt = systemPromptTemplate.create(Map.of("scenes", scenes));

        // --- 步骤 2: 调用AI并获取结构化结果 ---
        // 这里期望返回的结果已经更新，能自动匹配到我们修改后的 NluResult 和 ExtractedEntity record
        NluResult rawResult = this.chatClient.prompt()
                .system(prompt.getContents())
                .user(userText)
                .call()
                .entity(NluResult.class);

        logger.info("Raw NLU result from AI: {}", rawResult);

        // --- 步骤 3: 代码层面的健壮性处理 (过滤冗余实体) ---
        // 即使我们在提示词中要求模型不要返回冗余的REASON实体，但模型有时仍可能不遵守。
        // 在代码层面增加一道过滤，可以确保系统的最终稳定性，这是一种很好的防御性编程实践。
//        List<ExtractedEntity> filteredEntities = rawResult.entities().stream()
//                .filter(entity -> !"REASON".equalsIgnoreCase(entity.type()))
//                .collect(Collectors.toList());

        // 使用过滤后的实体列表，创建一个新的、更干净的 NluResult 对象返回给上层服务
        //NluResult finalResult = new NluResult(rawResult.scene(), filteredEntities);

        //logger.info("Filtered, final NLU result: {}", finalResult);

        return rawResult;
    }
}